﻿/* Copyright 2006, 2007 Christophe Jeannin

    This file is part of xch.

    xch is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    xch is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with xch; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "xch.h"

DWORD serverip;
SOCKET tehsock;
char buffer[600];

int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	INT_PTR mode;
	int s;

	InitCommonControls();

	mode = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_STARTUP), NULL, StartupDlgProc, 0);

	switch(mode)
	{
	case XCH_CONNECT:
		if(ConnectProc())
		{
			int r = recv(tehsock, buffer, 4, 0);
			if((r < 4) || (r == SOCKET_ERROR) || (*(DWORD*)(buffer) != XCH_TEST))
			{
				MessageBox(NULL, _T("Error receiving data."), NULL, MB_OK);
			}
			else
			{
				*(WORD*)(buffer) = XCH_OK;

				s = send(tehsock, buffer, 2, 0);
				if((s < 2) || (s == SOCKET_ERROR))
				{
					MessageBox(NULL, _T("Error sending data."), NULL, MB_OK);
				}
				else
				{
					DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc, 0);
				}
			}
		}
		else
		{
			MessageBox(NULL, _T("Couldn't connect."), NULL, MB_OK);
		}
		break;

	case XCH_LISTEN:
		if(tehsock = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_LISTEN), NULL, ListenDlgProc, 0))
		{
			*(DWORD*)(buffer) = XCH_TEST;
			s = send(tehsock, buffer, 4, 0);

			if((s < 4) || (s == SOCKET_ERROR))
			{
				MessageBox(NULL, _T("Error sending data."), NULL, MB_OK);
			}
			else
			{
				int r = recv(tehsock, buffer, 2, 0);

				if((r < 2) || (r == SOCKET_ERROR) || (*(WORD*)(buffer) != XCH_OK))
				{
					MessageBox(NULL, _T("Error receiving data."), NULL, MB_OK);
				}
				else
				{
					DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc, 0);
				}
			}
		}
		break;
	}

	WSACleanup();
	return 0;
}



INT_PTR CALLBACK StartupDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
	case WM_INITDIALOG:
		SendMessage(GetDlgItem(hwndDlg, IDC_RBN2), BM_SETCHECK, BST_CHECKED, 0);
		SendMessage(GetDlgItem(hwndDlg, IDC_IPA1), IPM_SETADDRESS, 0, XCH_SERVERADDR);
		return TRUE;

	case WM_CLOSE:
		EndDialog(hwndDlg, FALSE);
		return TRUE;

	case WM_COMMAND:
		if((HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == IDC_BTN1))
		{
			if(SendMessage(GetDlgItem(hwndDlg, IDC_RBN2), BM_GETCHECK, 0, 0) == BST_CHECKED)
			{
				DWORD ipaddr;
				if((SendMessage(GetDlgItem(hwndDlg, IDC_IPA1), IPM_GETADDRESS, 0, (LPARAM)(&ipaddr)) < 4) || !ipaddr)
				{
					MessageBox(hwndDlg, _T("Invalid IP address."), NULL, MB_OK);
					SetFocus(GetDlgItem(hwndDlg, IDC_IPA1));
				}
				else
				{
					serverip = ipaddr;
					EndDialog(hwndDlg, XCH_CONNECT);
				}
			}
			else
			{
				EndDialog(hwndDlg, XCH_LISTEN);
			}
			return TRUE;
		}
		else
		{
			return FALSE;
		}

	default:
		return FALSE;
	}
}



SOCKET InitWinsock()
{
	WSADATA sif;

	WSAStartup(MAKEWORD(1,1), &sif);
	return socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
}



BOOL ConnectProc()
{
	struct sockaddr_in srvinfo;

	srvinfo.sin_family = AF_INET;
	srvinfo.sin_port = XCH_PORT;
	srvinfo.sin_addr.s_addr = htonl(serverip);

	tehsock = InitWinsock();

	if(!connect(tehsock, (SOCKADDR*) &srvinfo, sizeof(srvinfo)))
	{
		return TRUE;
	}

	return FALSE;
}



INT_PTR CALLBACK MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	TCHAR text[512];
	int length;

	switch(uMsg)
	{
	case WM_INITDIALOG:
		SendMessage(GetDlgItem(hwndDlg, IDC_EDIT), EM_SETLIMITTEXT, 511, 0);
		CreateThread(NULL, 0, MainThread, hwndDlg, 0, NULL);
		return TRUE;

	case WM_CLOSE:
		*(DWORD*)(buffer) = XCH_QUIT;
		send(tehsock, buffer, 4, 0);
		Sleep(XCH_CLOSEDELAY);
		closesocket(tehsock);
		EndDialog(hwndDlg, FALSE);
		return TRUE;

	case WM_COMMAND:
		if(HIWORD(wParam) == BN_CLICKED)
		{
			switch(LOWORD(wParam))
			{
			case IDC_SEND:
				SendMessage(GetDlgItem(hwndDlg, IDC_EDIT), WM_GETTEXT, 512, (LPARAM)text);
				length = WideCharToMultiByte(CP_UTF8, 0, text, -1, buffer, 600, NULL, NULL);
				send(tehsock, buffer, length, 0);
				return TRUE;

			case IDC_TOP:
				if(IsDlgButtonChecked(hwndDlg, IDC_TOP) == BST_CHECKED)
				{
					SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
				}
				else
				{
					SetWindowPos(hwndDlg, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
					SetWindowPos(hwndDlg, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
				}
				return TRUE;

			default:
				return FALSE;
			}
		}
		else
		{
			return FALSE;
		}

	case XCH_TERMINATE:
		closesocket(tehsock);
		EndDialog(hwndDlg, FALSE);
		return TRUE;

	case XCH_TERMSIG:
		SendMessage(hwndDlg, WM_CLOSE, 0, 0);
		return TRUE;

	case XCH_INCOMING:
		MultiByteToWideChar(CP_UTF8, 0, buffer, -1, text, 512);
		SendMessage(GetDlgItem(hwndDlg, IDC_EDIT), WM_SETTEXT, 0, (LPARAM)text);
		return TRUE;

	default:
		return FALSE;
	}
}



DWORD WINAPI MainThread(LPVOID hDlg)
{
	int r;
	HWND hwnd = (HWND)hDlg;

	for(;;)
	{
		 r = recv(tehsock, buffer, 600, 0);

		 if((r == 0) || (r == SOCKET_ERROR))
		 {
			 MessageBox(hwnd, _T("Other peer disconnected."), NULL, MB_OK);
			 SendMessage(hwnd, XCH_TERMINATE, 0, 0);
			 break;
		 }
		 else
		 {
			 if(*(DWORD*)(buffer) == XCH_QUIT)
			 {
				 SendMessage(hwnd, XCH_TERMSIG, 0, 0);
				 break;
			 }

			 SendMessage(hwnd, XCH_INCOMING, (WPARAM)r, 0);
		 }

	}

	return 0;
}



INT_PTR CALLBACK ListenDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
	case WM_INITDIALOG:
		CreateThread(NULL, 0, ListenThread, hwndDlg, 0, NULL);
		SetTimer(hwndDlg, XCH_TIMER, 400, NULL);
		return TRUE;

	case WM_TIMER:
		if(wParam == XCH_TIMER)
		{
			SendMessage(GetDlgItem(hwndDlg, IDC_PGBLISTEN), PBM_STEPIT, 0, 0);
			return TRUE;
		}
		return FALSE;

	case WM_CLOSE:
		KillTimer(hwndDlg, XCH_TIMER);
		EndDialog(hwndDlg, FALSE);
		return TRUE;

	case WM_COMMAND:
		if((HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == ID_CANCEL))
		{
			SendMessage(hwndDlg, WM_CLOSE, 0, 0);
			return TRUE;
		}
		return FALSE;

	case XCH_CONNECTED:
		KillTimer(hwndDlg, XCH_TIMER);
		EndDialog(hwndDlg, wParam);
		return TRUE;

	default:
		return FALSE;
	}
}



DWORD WINAPI ListenThread(LPVOID hDlg)
{
	HWND hwnd = (HWND)hDlg;
	struct sockaddr_in srvinfo;

	srvinfo.sin_family = AF_INET;
	srvinfo.sin_port = XCH_PORT;
	srvinfo.sin_addr.s_addr = 0;	// 0.0.0.0 listen on all interfaces

	tehsock = InitWinsock();
	bind(tehsock, (SOCKADDR*) &srvinfo, sizeof(srvinfo));
	if(!listen(tehsock, 1))
	{
		SOCKET s;
		while((s = accept(tehsock, NULL, 0)) == SOCKET_ERROR);
		SendMessage(hwnd, XCH_CONNECTED, (WPARAM)s, 0);
	}
	else
	{
		MessageBox(hwnd, _T("Couldn't start listening."), NULL, MB_OK);
		SendMessage(hwnd, XCH_CONNECTED, FALSE, 0);
	}

	closesocket(tehsock);
	return 0;
}
